﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace StockMatch.Service
{
    public static class Logger
    {
        /// <summary>
        /// 日志保存的文件名，文件名中可以包含动态系统时间。
        /// 例如：
        /// "c:\\sqllog\\{yyyyMMdd_HH}.txt"，表示在c盘sqllog目录下每小时生成一个文件
        /// "c:\\sqllog\\{yyyyMMdd_HHmm}.txt"，表示在c盘sqllog目录下每分钟生成一个文件
        /// </summary>
        internal static string FileName
        {
            get
            {
                if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["LoggerPath"]))
                {
                    throw new Exception("请配置LoggerPath");
                }
                return ConfigurationManager.AppSettings["LoggerPath"];
            }
        }

        internal static bool IsRunDebugMode
        {
            get
            {
                if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["IsRunDebugMode"]))
                {
                    throw new Exception("请配置IsRunDebugMode");
                }
                return bool.Parse(ConfigurationManager.AppSettings["IsRunDebugMode"]);
            }
        }


        /// <summary>
        /// 根据当前系统时间和配置的FileName属性获取真实文件名
        /// </summary>
        /// <returns></returns>
        private static string GetActualFileName()
        {
            string file = FileName;
            Regex regex = new Regex("[\\{]{1}[^\\{\\}]*[\\}]{1}");
            MatchCollection ms = regex.Matches(file);
            if (ms != null)
            {
                foreach (Match m in ms)
                {
                    DateTime now = DateTime.Now;
                    file = file.Replace(m.Value, now.ToString(m.Value.Substring(1, m.Length - 2)));
                }
            }
            return file;
        }

        private static readonly object _lockObject = new object();
        private static string _currentFileName = "";
        private static StreamWriter _writer;
        private static FileStream _fs;
        private static void WriteLog(string message)
        {
            string fileName = GetActualFileName();
            if (fileName != _currentFileName)
            {
                lock (_lockObject)
                {
                    if (fileName != _currentFileName)
                    {
                        if (_writer != null)
                        {
                            //说明上次已经打开需要先关闭
                            try
                            {
                                _writer.Close();
                                _fs.Close();
                            }
                            catch { }
                            _writer = null;
                            _fs = null;
                        }
                        FileInfo fi = new FileInfo(fileName);
                        if (!fi.Directory.Exists) fi.Directory.Create();
                        _fs = new FileStream(fileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
                        _writer = new StreamWriter(_fs, Encoding.UTF8);
                        _currentFileName = fileName;
                    }
                }
            }

            lock (_lockObject)
            {
                _writer.Write(DateTime.Now.ToString());
                _writer.Write("\t");
                _writer.Write(message);
                _writer.Write("\r\n");
                _writer.Flush();//设置了AutoFlush=true就不用flush
            }

        }

        /// <summary>
        /// 调用此方法的日志只会在测试模式下写日志
        /// </summary>
        /// <param name="message"></param>
        public static void Info(string message)
        {
            if (IsRunDebugMode)
            {
                WriteLog(message);
            }
        }


        /// <summary>
        /// 调用此方法的日志会在测试以及正式发布下写日志
        /// </summary>
        /// <param name="message"></param>
        public static void Error(string message)
        {
            WriteLog(message);
        }
    }
}
